package org.easymodelers.gmf.utils;

import java.io.IOException;

import org.easymodelers.gmf.creator.impl.ModelsManager;
import org.easymodelers.modeler.data.Element;
import org.easymodelers.modeler.data.ElementLabel;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.gmf.gmfgraph.Canvas;
import org.eclipse.gmf.gmfgraph.DiagramLabel;
import org.eclipse.gmf.gmfgraph.Node;
import org.eclipse.gmf.mappings.Mapping;
import org.eclipse.gmf.runtime.emf.core.resources.GMFResourceFactory;
import org.eclipse.gmf.tooldef.AbstractTool;
import org.eclipse.gmf.tooldef.CreationTool;
import org.eclipse.gmf.tooldef.ToolRegistry;

public abstract class GmfModelsUtils {

	// General methods

	private static String getURIMapping(String uri) {
		uri = uri.replace("platform:/", "");
		uri = uri.substring(uri.indexOf("/")+1);
		return uri;
	}
	
	public static <T> void createGmfModel(String modelPath, ModelCreatorCallback callback) throws IOException {
		ResourceSet resourceSet = new ResourceSetImpl();
		GMFResourceFactory resourceFactory = new GMFResourceFactory();
		resourceSet.getResourceFactoryRegistry()
				.getExtensionToFactoryMap().put(
						Resource.Factory.Registry.DEFAULT_EXTENSION,
						resourceFactory);

		final Resource resource = resourceSet.createResource(URI.createPlatformResourceURI(modelPath, true));
		resourceSet.getURIConverter().getURIMap().put(
				URI.createPlatformResourceURI(modelPath, true),
				URI.createURI(getURIMapping(modelPath)));
		EObject modelRootElement = callback.createModelRootElement();
		resource.getContents().add(modelRootElement);
		
		resource.save(null);
	}

	public static EObject loadResource(Resource resource) throws IOException {
		resource.load(null);
		EcoreUtil.resolveAll(resource);
		return (EObject) EcoreUtil.getObjectByType(
                resource.getContents(), EcorePackage.eINSTANCE.getEObject());
	}

	public static EObject loadGmfModel(String modelPath) throws IOException {
		ResourceSet resourceSet = new ResourceSetImpl();
		GMFResourceFactory resourceFactory = new GMFResourceFactory();
		resourceSet.getResourceFactoryRegistry()
				.getExtensionToFactoryMap().put(
						Resource.Factory.Registry.DEFAULT_EXTENSION,
						resourceFactory);

		final Resource resource = resourceSet.createResource(URI.createPlatformResourceURI(modelPath, true));
		resourceSet.getURIConverter().getURIMap().put(
				URI.createPlatformResourceURI(modelPath, true),
				URI.createURI(getURIMapping(modelPath)));
		resource.load(null);
		EcoreUtil.resolveAll(resource);

		return (EObject) EcoreUtil.getObjectByType(
                resource.getContents(), EcorePackage.eINSTANCE.getEObject());
	}

	public static EObject loadEcoreModel(String modelPath) throws IOException {
		ResourceSet resourceSet = new ResourceSetImpl();
		EcoreResourceFactoryImpl resourceFactory = new EcoreResourceFactoryImpl();
		resourceSet.getResourceFactoryRegistry()
				.getExtensionToFactoryMap().put(
						Resource.Factory.Registry.DEFAULT_EXTENSION,
						resourceFactory);

		final Resource resource = resourceSet.createResource(URI.createPlatformResourceURI(modelPath, true));
		resourceSet.getURIConverter().getURIMap().put(
				URI.createPlatformResourceURI(modelPath, true),
				URI.createURI(getURIMapping(modelPath)));
		resource.load(null);
		EcoreUtil.resolveAll(resource);

		return (EObject) EcoreUtil.getObjectByType(
                resource.getContents(), EcorePackage.eINSTANCE.getEObject());
	}
	
	public static EPackage getMetaModel(String metaModelPath) throws IOException {
		return (EPackage)loadEcoreModel(metaModelPath);
	}

	// Graph model

	public static Canvas getGmfGraphModel(String gmfGraphModelPath) throws IOException {
		return (Canvas) loadGmfModel(gmfGraphModelPath);
	}
	
	public static Node getNodeForElement(Element element, Canvas canvas) {
		for (Node node : canvas.getNodes()) {
			//System.out.println("node = "+node.getName());
			if ((element.getName()+"Node").equals(node.getName())) {
				return node;
			}
		}
		return null;
	}
	
	public static DiagramLabel getDiagramLabelForLabel(ElementLabel elementLabel, Canvas canvas) {
		for (Node node : canvas.getNodes()) {
			if (node instanceof DiagramLabel) {
			//System.out.println("node = "+node.getName());
				if ((elementLabel.getName()+"DiagramLabel").equals(node.getName())) {
					return (DiagramLabel)node;
				}
			}
		}
		return null;
	}
	
	// Tool model
	
	public static ToolRegistry getGmfToolModel(String gmfToolPath) throws IOException {
		return (ToolRegistry) loadGmfModel(gmfToolPath);
	}
	
	public static AbstractTool getToolForElement(Element element, ToolRegistry toolRegistry) {
		for (TreeIterator<EObject> i = toolRegistry.eAllContents(); i.hasNext(); ) {
			EObject o = i.next();
			if (o instanceof CreationTool) {
				CreationTool tool = (CreationTool) o;
				//System.out.println("tool = "+tool.getTitle());
				if (("Create "+element.getName()).equals(tool.getTitle())) {
					return tool;
				}
			}
		}
		return null;
	}

	// Map model
	
	public static Mapping getGmfMapModel(String gmfMapPath) throws IOException {
		return (Mapping) loadGmfModel(gmfMapPath);
	}
	
}
